package cn.school.system.service.pay;

import cn.school.common.annotation.Excel;
import cn.school.common.constant.enums.DataStatusEnum;
import cn.school.common.constant.enums.OrderTypeEnum;
import cn.school.common.constant.enums.PayStatusEnum;
import cn.school.system.config.FriendsConfig;
import cn.school.system.domain.*;
import cn.school.system.mapper.BiExtractPaperMapper;
import cn.school.system.service.*;
import com.alibaba.fastjson2.JSONObject;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import com.wechat.pay.java.service.retailstore.model.OrderInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zsj
 * @version 1.0
 * @date 2023/12/13 10:10
 * @desc
 **/
@Slf4j
@Service
public class WxPayService {
    public static Map<String,Config> configMap = new HashMap<>();

    @Autowired
    private FriendsConfig friendsConfig;
    @Autowired
    private IBiOrderInfoService orderService;
    @Autowired
    private IBiPaperService biPaperService;
    @Autowired
    private IBiShopService biShopService;
    @Autowired
    private IBiCommissionService biCommissionService;
    @Autowired
    private IBiExtractPaperService biExtractPaperService;

    //支付通知回调
    @Transactional(rollbackFor = Exception.class)
    public String payNotify(HttpServletRequest request, String requestBody) throws Exception {
        log.info("微信原生支付回调body参数：" + requestBody);

        String signature = request.getHeader("Wechatpay-Signature");
        log.info("Wechatpay-Signature：" + signature);
        String nonce = request.getHeader("Wechatpay-Nonce");
        log.info("Wechatpay-Nonce：" + nonce);
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        log.info("Wechatpay-Timestamp：" + timestamp);
        String serialNumber = request.getHeader("Wechatpay-Serial");
        log.info("Wechatpay-Serial：" + serialNumber);
        String signatureType = request.getHeader("Wechatpay-Signature-Type");
        log.info("Wechatpay-Signature-Type：" + signatureType);

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
        // 没有的话，则构造一个
        NotificationConfig config = (NotificationConfig) getWxPayConfig();
        if (config == null) {
            throw new Exception("获取微信支付配置失败");
        }

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        if (parser == null) {
            throw new Exception("初始化NotificationParser失败");
        }

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (parser == null) {
            throw new Exception("验签/解密参数失败");
        }

        log.info("解密后参数为：{}", JSONObject.toJSONString(transaction));

        //支付金额（单位：分）
        TransactionAmount transactionAmount = transaction.getAmount();
        //转换支付金额 分=>元
        BigDecimal amount = new BigDecimal(transactionAmount.getPayerTotal()).divide(new BigDecimal(100));

        Long orderId = new Long(transaction.getAttach());
        BiOrderInfo order = orderService.selectBiOrderInfoById(orderId);
        if(order.getPayStatus().equals(PayStatusEnum.CREATE.getStatus())) {
            if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
                log.info("支付回调：订单{}，金额：{}元，支付成功", order.getMchPayOrderNo(), amount);

                BiOrderInfo tempOrder = new BiOrderInfo();
                tempOrder.setId(orderId);
                tempOrder.setWxPayOrderNo(transaction.getTransactionId());
                tempOrder.setPayStatus(PayStatusEnum.SUCCESS.getStatus());
                SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
                Date parsedDateTime = inputFormat.parse(transaction.getSuccessTime());
                tempOrder.setPaySucTime(parsedDateTime);

                if(order.getOrderType()== OrderTypeEnum.TIAN_JIA.getStatus()){
                    //将纸条更新为可用状态
                    BiPaper paper = new BiPaper();
                    paper.setId(order.getPaperId());
                    paper.setStatus(DataStatusEnum.USABLE.getStatus());
                    biPaperService.updateBiPaper(paper);
                }else if (order.getOrderType()== OrderTypeEnum.CHOU_QU.getStatus()){
                    //抽取纸条
                    List<Long> extractList = biPaperService.extractPaper(order.getOpenid(), order.getGoodId(), order.getCqSchoolId(),null);
                    String paperIds = null;
                    for (int i = 0; i < extractList.size(); i++) {
                        if(paperIds!=null){
                            paperIds = paperIds +"," + extractList.get(i);
                        }else{
                            paperIds = ""+extractList.get(i);
                        }
                    }

                    //设置订单抽取到的纸条
                    tempOrder.setPaperIds(paperIds);

                    List<BiExtractPaper> extractPaperList = new ArrayList<>();

                    for (Long paperId:extractList) {
                        BiExtractPaper extractPaper = new BiExtractPaper();
                        extractPaper.setOpenid(order.getOpenid());
                        extractPaper.setStatus(DataStatusEnum.USABLE.getStatus());
                        extractPaper.setPaperId(paperId);
                        extractPaper.setOrderId(order.getId());

                        extractPaperList.add(extractPaper);
                    }

                    biExtractPaperService.insertBiExtractPaperList(extractPaperList);

                }else if(order.getOrderType()==OrderTypeEnum.KAI_TONG_DIAN_PU.getStatus()){
                    BiShop shop = new BiShop();
                    shop.setId(order.getShopId());
                    shop.setStatus(DataStatusEnum.USABLE.getStatus());
                    shop.setPassTime(new Date());
                    biShopService.updateBiShop(shop);
                }

                //计算订单信息
                countRecommendShopAmount(order);

                orderService.updateBiOrderInfo(tempOrder);
            }else{
                log.info("支付回调：订单{}，金额：{}元，支付结果：{}", order.getMchPayOrderNo(), amount, transaction.getTradeStateDesc());
            }
        }else{
            log.info("支付回调：订单{}，已处理", order.getMchPayOrderNo());
        }

        return "success";
    }


    //获取推荐店铺佣金
    private void countRecommendShopAmount(BiOrderInfo oi){
        //处理佣金
        if(oi.getRecommendShopId()==null || oi.getRecommendShopId().intValue()<=0){
            log.info("{}，订单无推荐人，不执行分佣", oi.getId());
            return;
        }

        if(oi.getPayAmount().compareTo(BigDecimal.ZERO)<1){
            log.info("{}，订单支付金额为0，不执行分佣", oi.getId());
            return;
        }

        BiCommission temp = new BiCommission();
        temp.setOrderId(String.valueOf(oi.getId()));
        List<BiCommission> list = biCommissionService.selectBiCommissionList(temp);
        if(list!=null && list.size()>0){
            log.info("{}，订单已执行分佣，不重复执行分佣", oi.getId());
            return;
        }

        BiShop shop = biShopService.selectBiShopById(oi.getRecommendShopId());

        BigDecimal amount = oi.getPayAmount().multiply(shop.getPercentage()).divide(new BigDecimal(100));

        BiCommission biCommission = new BiCommission();
        biCommission.setStatus(DataStatusEnum.USABLE.getStatus());
        biCommission.setAmount(amount);
        biCommission.setGoodName(oi.getGoodName());
        biCommission.setShopId(shop.getId());
        biCommission.setShopPhone(shop.getPhone());
        biCommission.setOpenid(shop.getOpenid());

        //添加佣金明细记录
        biCommissionService.insertBiCommission(biCommission);

        //添加店铺账户余额
        biShopService.addShopCashFee(amount,shop.getId());
    }

    //创建支付预订单
    public PrepayWithRequestPaymentResponse createPayPreOrder(BiOrderInfo oi) throws Exception{
        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
        Config config = getWxPayConfig();

        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();

        // 跟之前下单示例一样，填充预下单参数
        PrepayRequest request = new PrepayRequest();
        request.setMchid(friendsConfig.getMerchantId());
        request.setAppid(friendsConfig.getWxAppid());

        Amount amount = new Amount();
        amount.setTotal(oi.getPayAmount().multiply(new BigDecimal(100)).intValue());
        request.setAmount(amount);

        request.setDescription("订单-"+oi.getMchPayOrderNo());
        request.setOutTradeNo(oi.getMchPayOrderNo());
        request.setAttach(String.valueOf(oi.getId()));
        request.setNotifyUrl(friendsConfig.getNotifyUrl());

        Payer payer = new Payer();
        payer.setOpenid(oi.getOpenid());
        request.setPayer(payer);

        PrepayWithRequestPaymentResponse res = service.prepayWithRequestPayment(request);

        log.info("请求支付参数：{}",JSONObject.toJSONString(res));

        return res;
    }

    //获取配置
    private Config getWxPayConfig() {
        if(configMap.containsKey(friendsConfig.getMerchantId())){
            return configMap.get(friendsConfig.getMerchantId());
        }else {
            // 使用自动更新平台证书的RSA配置
            // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
            Config config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(friendsConfig.getMerchantId()) //商户号
                    .privateKeyFromPath(friendsConfig.getPrivateKeyFromPath()) //商户API私钥路径
                    .merchantSerialNumber(friendsConfig.getMerchantSerialNumber())  //商户证书序列号
                    .apiV3Key(friendsConfig.getApiV3Key()) //商户APIV3密钥
                    .build();
            configMap.put(friendsConfig.getMerchantId(),config);
            return config;
        }
    }
}
